﻿/// Jasig CAS server emulation with ASP.NET
/// by Uli Trampe
/// http://jasigemu.codeplex.com/
/// 
using System;
using System.Web;
using System.Web.Caching;

namespace Codeplex.JasigEmu
{
    /// <summary>
    /// Representation of a temporary CAS service validation ticket
    /// </summary>
    public class CasTicket
    {
        private static uint nCounter = 0;

        private string strUserName;
        private string strService;

        private CasTicket(string strUserName, string strService)
        {
            this.strUserName = strUserName;
            this.strService = strService;
        }

        /// <summary>
        /// Issue a CAS ticket and store it temporarily in the context cache
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="strUserName"></param>
        /// <param name="strService"></param>
        /// <returns>Returns the corresponding ticket string.</returns>
        public static string Issue(HttpContext httpContext, string strUserName, string strService)
        {
            // create the ticket
            CasTicket ticket = new CasTicket(strUserName, strService);

            // create 120 bit random data
            byte[] rdata = new byte[15];
            Random random = new Random(DateTime.Now.Millisecond);
            random.NextBytes(rdata);

            // convert random data to an URL save token of 20 characters length
            string strToken = HttpServerUtility.UrlTokenEncode(rdata);

            // build the CAS ticket string
            string strTicket = "ST-" + (++nCounter).ToString() + "-" + strToken + "-cas";

            // store ticket in context cache
            httpContext.Cache.Add(strTicket, ticket, null, DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);

            return strTicket;
        }

        /// <summary>
        /// Read a ticket from cache, check and immedeately invalidate (punch) it
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="strTicket"></param>
        /// <param name="strService">Returns the corresponding service</param>
        /// <returns>Returns the corresponding user name</returns>
        public static string CheckAndPunch(HttpContext httpContext, string strTicket, ref string strService)
        {
            // load ticket from context cache
            CasTicket ticket = httpContext.Cache.Get(strTicket) as CasTicket;
            if (ticket == null) return "";

            // remove ticket from cache
            httpContext.Cache.Remove(strTicket);

            // return ticket data
            strService = ticket.strService;
            return ticket.strUserName;
        }
    }
}
